Shell脚本实战05-解决DOS攻击

1. 解决DOS攻击

写一个Shell脚本解决类DDoS攻击的生产案例。请根据Web日志或系统网络连接数,监控某个IP的并发连接数,若短时间内PV达到100,即调用防火墙命令封掉对应的IP。防火墙命令为:iptables -I INPUT -s IP地址 -j DROP

2. 参考答案1

先分析Web日志,可以每分钟或每小时分析一次,这里给出按小时处理的方法。可以将日志按小时进行分割,分成不同的文件,根据分析结果把PV数高的单IP封掉。例如,每小时单IP的PV数超过500,则即刻封掉,这里简单地把日志的每一行近似看作一个PV,实际工作中需要计算实际页面的数量,而不是请求页面元素的数量,另外,很多公司都是以NAT形式上网的,因此每小时单IP的PV数超过多少就会被封掉,还要根据具体的情况具体分析,本体仅给出一个实现的案例,在以后参考的时候需要考虑自身网站的业务去使用。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
file=$1 #<==定义一个变量接收命令行传参,参数为日志文件类型
while true
do
awk '{print $1}' $1 | grep -v "^$" | sort | uniq -c > /tmp/tmp.log
#<==分析传入的日志文件,并在排序去重后追加到一个临时文件里
exec < /tmp/tmp.log #<==读取上述临时文件
while read line
do
ip=`echo $line | awk '{print $2}'` #<==获取文件中的每一行的第二列
count=`echo $line | awk '{print $1}'` #<==获取文件中的每一行的第一列
if [ $count -gt 500 ] && [ `iptables -L -n | grep "$ip" | wc -l` -lt 1 ]
#<==如果PV数大于500,并且防火墙里没有封过此IP
then
iptables -I INPUT -s $ip -j DROP #<==则封掉PV数大于500的IP
echo "$line is dropped" >> /tmp/droplist_$(date +%F).log
#<==记录处理日志
fi
done
sleep 3600 #<==还可以按分钟进行分析,不过日hi的分割或过滤也得按分钟才行。
done

3. 参考答案2

分析Linux系统的网络连接数,而不是分析Web日志。

设计思路:

首先要分析单IP占网络连接数的情况,即取当前网络连接状体为ESTABLISHED的行数,然后分析对应客户端列不通IP连接数量的排序,对排序比较高的IP进行封堵。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
file=$1 #<==定义一个变量以接收命令行传参,参数为日志文件类型。
#==实际工作中可以先使用netstat命令将网络状态生成临时文件,然后再传参给$1
if expr "$file" : ".*\.log" &> /dev/null #<==expr的用法,判断扩展名是否以.log结尾
then
: #<==这个冒号表示什么都不做
else
echo $"usage:$0 xxx.log" #<==对不符合扩展名类型的给出正确提示
exit 1 #<==退出脚本
fi
while true
do
grep "ESTABLISHED" $1 | awk -F "[ :]+" '{ ++S[$(NF-3)]}END {for(key in S) print S[key], key}' | sort -rn -k1 | head -5 > /tmp/tmp.log
#<==分析传入的网络状态日志,获取到客户端IP列的信息,并去重排序
while read line
do
ip=`echo $line | awk '{print $2}'
count=`echo $line | awk '{print $1}'`
if [ $count -gt 500 ] && [ `iptables -L -n | grep "$ip" | wc -l` -lt 1 ]
then
iptables -I INPUT -s $ip -j DROP
echo "$line is dropped" >> /tmp/droplist_$(date +%F).log
fi
done</tmp/tmp.log
sleep 180
done

提示:对于分钟级别的频率任务,也可以不用while,而用定时任务来实现。

4. 参考答案3

此解决问题的方案和答案2一样,只不过它的写法更专业,分模块实现的。脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash
file=$1
JudgeExt(){ #<==定义判断扩展名的函数,可以传入日志文件
if expr "$1" : ".*\.log" &> /dev/null
then
:
else
echo $"usage:$0 xxx.log"
exit 1
fi
}
IpCount(){ #<==分析日志,对访问的IP去重排序
grep "ESTABLISHED" $1 | awk -F "[ :]+" '{ ++S[$(NF-3)]}END {for(key in S) print S[key], key}' | sort -rn -k1 | head -5 >/tmp/tmp.log
}
ipt(){ #<==防火墙封堵函数
local ip=$1
if [ `iptables -L -n | grep "$ip" | wc -l` -lt 1 ]
then
iptables -I INPUT -s $ip -j DROP
echo "$line is dropped" >> /tmp/droplist_$(date +F).log
fi
}
main(){ #<==定义主函数
JudgeExt $file
while true
do
IpCount $file
while read line
do
ip=`echo $line | awk '{print $2}'`
count=`echo $line | awk '{print $1}'`
if [ $count -gt 3 ]
then
ipt $ip
fi
done</tmp/tmp.log
sleep 180
done
}
main

0%